home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
PowerPlant
/
LPasswordField
/
LPasswordField.cp
< prev
next >
Wrap
Text File
|
1995-11-03
|
31KB
|
1,351 lines
/* NAME:
LPasswordField.cp
WRITTEN BY:
Dair Grant, dair@kagi.com
DESCRIPTION:
A Pane containing editable text, which only displays bullet characters.
Use an LPasswordField for small amounts of monstyled text, such as a
text entry field in a dialog box. LPasswordField derives from the
LEditField class, so similar restrictions apply to its usage (it uses
TextEdit, and it's not a View, so you can't put a PasswordField in a
Scroller).
LPasswordField should behave *exactly* like EditFields, the only
difference being that characters are always displayed as bullets.
You use the same routines (SetDescriptor/GetDescriptor and SetValue/
GetValue) to manipulate the text, and the same commands can be
performed on it (cut, copy, paste, etc). The LPasswordField takes
care of ensuring that only bullets are ever displayed.
The bullet character defaults to '•'. The SetBullet method allows
this to be changed.
To use a LPasswordField, create and position an EditField with
Constructor, and set the class ID to 'pass' once you're happy with
it. Then include LPasswordField.h in the relevent source files,
add LPasswordField.cp to your project, and put the line
URegistrar::RegisterClass(LPasswordField::class_ID,
LPasswordField::CreatePasswordFieldStream);
in your applications constructor.
You may use the LPasswordField class in any project you write,
without restriction. Comments, bugs, or suggestions are more than
welcome - send them to dair@kagi.com.
___________________________________________________________________________
VERSION HISTORY:
1.0: (June 1995, dg)
• First public release.
___________________________________________________________________________
*/
//=============================================================================
// Include files
//-----------------------------------------------------------------------------
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include <Scrap.h>
#include <Script.h>
#include <TextEdit.h>
#include <ToolUtils.h>
#include <LCommander.h>
#include <LEditField.h>
#include <LPane.h>
#include <LPasswordField.h>
#include <LStream.h>
#include <PP_KeyCodes.h>
#include <PP_Messages.h>
#include <UDrawingState.h>
#include <UKeyFilters.h>
#include <UTETextAction.h>
#include <UTextTraits.h>
//=============================================================================
// Private defines
//-----------------------------------------------------------------------------
#define kHiddenTEOffset 1000 // Offset for hidden TE record
//=============================================================================
// LPasswordField::CreatePasswordFieldStream
//-----------------------------------------------------------------------------
// Create a new PasswordField object from the data in a Stream.
//-----------------------------------------------------------------------------
LPasswordField *LPasswordField::CreatePasswordFieldStream(LStream *inStream)
{
return (new LPasswordField(inStream));
}
//=============================================================================
// LPasswordField::LPasswordField
//-----------------------------------------------------------------------------
// Default constructor.
//-----------------------------------------------------------------------------
LPasswordField::LPasswordField() : LEditField()
{
InitPassField(editAttr_Box);
}
//=============================================================================
// LPasswordField::LPasswordField
//-----------------------------------------------------------------------------
// Copy constructor.
//-----------------------------------------------------------------------------
LPasswordField::LPasswordField(const LPasswordField &inOriginal) : LEditField(inOriginal)
{ Rect viewRect = {0, 0, 0, 0};
Str255 theStr;
// The LEditField constructor will have build our mTextEditH member.
// We move it somewhere off screen so it won't be visible.
::OffsetRect(&(*mTextEditH)->viewRect, kHiddenTEOffset, kHiddenTEOffset);
// Create the 'bullet' TextEdit record
mBulletTextEditH = ::TENew(&viewRect, &viewRect);
// Set our descriptor correctly and align everything correctly
SetDescriptor(inOriginal.GetDescriptor(theStr));
AlignTextEditRects();
}
//=============================================================================
// LPasswordField::LPasswordField
//-----------------------------------------------------------------------------
// Construct from input parameters.
//-----------------------------------------------------------------------------
LPasswordField::LPasswordField(const SPaneInfo &inPaneInfo,
Str255 inString,
ResIDT inTextTraitsID,
Int16 inMaxChars,
Boolean inHasBox,
Boolean inHasWordWrap,
KeyFilterFunc inKeyFilter,
LCommander *inSuper) :
LEditField(inPaneInfo, inString, inTextTraitsID, inMaxChars,
inHasBox, inHasWordWrap, inKeyFilter, inSuper)
{ Uint8 attributes = 0;
// Set our attributes, then initialise ourself with them
if (inHasBox)
attributes += editAttr_Box;
if (inHasWordWrap)
attributes += editAttr_WordWrap;
InitPassField(attributes);
// If we've been given a string, put it into the visible
// TextEdit record and convert it to bullets
if (inString[0] > 0)
{
::TESetText(inString + 1, inString[0], mBulletTextEditH);
SetTextToBullets(mBulletTextEditH);
}
// Align the TextEdit records and select the text, if any
AlignTextEditRects();
SelectAll();
}
//=============================================================================
// LPasswordField::LPasswordField
//-----------------------------------------------------------------------------
// Construct from input parameters.
//-----------------------------------------------------------------------------
LPasswordField::LPasswordField(const SPaneInfo &inPaneInfo,
Str255 inString,
ResIDT inTextTraitsID,
Int16 inMaxChars,
Uint8 inAttributes,
KeyFilterFunc inKeyFilter,
LCommander *inSuper) :
LEditField(inPaneInfo, inString, inTextTraitsID, inMaxChars,
inAttributes, inKeyFilter, inSuper)
{
// Initialise ourselves with the supplied attributes
InitPassField(inAttributes);
// If we've been given a string, put it into the visible
// TextEdit record and convert it to bullets
if (inString[0] > 0)
{
::TESetText(inString + 1, inString[0], mBulletTextEditH);
SetTextToBullets(mBulletTextEditH);
}
// Align the TextEdit records and select the text, if any
AlignTextEditRects();
SelectAll();
}
//=============================================================================
// LPasswordField::LPasswordField
//-----------------------------------------------------------------------------
// Construct from the data in a stream.
//-----------------------------------------------------------------------------
LPasswordField::LPasswordField(LStream *inStream) : LEditField(inStream)
{ Uint8 attributes = 0;
// The LEditField constructor has built itself from the data in
// inStream, but didn't save the attributes away anywhere. We
// have to recreate the attributes ourselves by hand.
if (mHasBox)
attributes |= editAttr_Box;
if (mHasWordWrap)
attributes |= editAttr_WordWrap;
if (TEFeatureFlag(teFAutoScr, teBitTest, mTextEditH) == teBitSet)
attributes |= editAttr_AutoScroll;
if (TEFeatureFlag(teFTextBuffering, teBitTest, mTextEditH) == teBitSet)
attributes |= editAttr_TextBuffer;
if (TEFeatureFlag(teFOutlineHilite, teBitTest, mTextEditH) == teBitSet)
attributes |= editAttr_OutlineHilite;
if (TEFeatureFlag(teFInlineInput, teBitTest, mTextEditH) == teBitSet)
attributes |= editAttr_InlineInput;
if (TEFeatureFlag(teFUseTextServices, teBitTest, mTextEditH) == teBitSet)
attributes |= editAttr_TextServices;
// Initialise ourselves from these attributes
InitPassField(attributes);
// Set the visible TextEdit record to match the hidden one
SetVisibleFromHidden();
// Align the TextEdit records and select the text, if any
AlignTextEditRects();
SelectAll();
}
//=============================================================================
// LPasswordField::InitPassField
//-----------------------------------------------------------------------------
// Initialise the member variables of a PassField.
//
// We also fudge some of the things our parent (LEditField) set up
// earlier.
//-----------------------------------------------------------------------------
void LPasswordField::InitPassField(Uint8 inAttributes)
{ Rect viewRect = {0, 0, 0, 0};
// The LEditField constructor will have build our mTextEditH member.
// We move it somewhere off screen so it won't be visible.
OffsetRect(&(*mTextEditH)->viewRect, kHiddenTEOffset, kHiddenTEOffset);
// Set the focus to be ourselves, rather than the EditField
StFocusAndClipIfHidden focus(this);
// Initialise our internal variables
mBulletTextEditH = ::TENew(&viewRect, &viewRect);
mBullet = '•';
// Set the optional features for the TextEdit field
::TEFeatureFlag(teFAutoScr,
((inAttributes & editAttr_AutoScroll) != 0) ?
teBitSet : teBitClear, mBulletTextEditH);
::TEFeatureFlag(teFTextBuffering,
((inAttributes & editAttr_TextBuffer) != 0) ?
teBitSet : teBitClear, mBulletTextEditH);
::TEFeatureFlag(teFOutlineHilite,
((inAttributes & editAttr_OutlineHilite) != 0) ?
teBitSet : teBitClear, mBulletTextEditH);
::TEFeatureFlag(teFInlineInput,
((inAttributes & editAttr_InlineInput) != 0) ?
teBitSet : teBitClear, mBulletTextEditH);
::TEFeatureFlag(teFUseTextServices,
((inAttributes & editAttr_TextServices) != 0) ?
teBitSet : teBitClear, mBulletTextEditH);
}
//=============================================================================
// LPasswordField::~LPasswordField
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
LPasswordField::~LPasswordField()
{
if (mBulletTextEditH != nil)
::TEDispose(mBulletTextEditH);
}
//=============================================================================
// LPasswordField::SetDescriptor
//-----------------------------------------------------------------------------
// Set the contents of a PasswordField from a Pascal string.
//
// We call our parent class to set the text of the offscreen item
// correctly, then resynch the visible field.
//-----------------------------------------------------------------------------
void LPasswordField::SetDescriptor(ConstStr255Param inDescriptor)
{
// Call our parent class
LEditField::SetDescriptor(inDescriptor);
// Resynch the visible field, and redraw
SetVisibleFromHidden();
Refresh();
}
//=============================================================================
// LPasswordField::SetBullet
//-----------------------------------------------------------------------------
// Set the bullet character to be used.
//-----------------------------------------------------------------------------
void LPasswordField::SetBullet(Int16 inBullet)
{
mBullet = inBullet;
Refresh();
}
//=============================================================================
// LPasswordField::SetTextTraitsID
//-----------------------------------------------------------------------------
// Set the text traits of the PasswordField.
//-----------------------------------------------------------------------------
void LPasswordField::SetTextTraitsID(ResIDT inTextTraitsID)
{
// Call our parent class for the off screen TextEdit record
LEditField::SetTextTraitsID(inTextTraitsID);
// Set the visible TextEdit record
UTextTraits::SetTETextTraits(mTextTraitsID, mBulletTextEditH);
}
//=============================================================================
// LPasswordField::DrawSelf
//-----------------------------------------------------------------------------
// Draw a PasswordField.
//-----------------------------------------------------------------------------
void LPasswordField::DrawSelf()
{ Rect frame;
// Calculate the local frame rectangle
CalcLocalFrameRect(frame);
// Draw a border if necessary
if (mHasBox)
{
DrawBox();
::InsetRect(&frame, 2, 2);
}
// A Mac TERec stores a pointer to its owner port We have to
// change it to the current port in case we are drawing into
// a port that is not the owner port. This happens when we are
// printing or drawing into an offscreen port.
GrafPtr savePort = (**mBulletTextEditH).inPort;
(**mBulletTextEditH).inPort = UQDGlobals::GetCurrentPort();
::TEUpdate(&frame, mBulletTextEditH);
(**mBulletTextEditH).inPort = savePort;
}
//=============================================================================
// LPasswordField::ClickSelf
//-----------------------------------------------------------------------------
// Respond to clicks inside a PasswordField.
//-----------------------------------------------------------------------------
void LPasswordField::ClickSelf(const SMouseDownEvent &inMouseDown)
{
// If we're not the target, then clicking in us makes us
// the target. Since TEClick will set a new selection
// ragen, we clear the current selection range to avoid
// an ugly flash.
if (!IsTarget())
{
::TESetSelect(0, 0, mTextEditH);
::TESetSelect(0, 0, mBulletTextEditH);
SwitchTarget(this);
}
// If we're the target, handle the click with TextEdit
if (IsTarget())
{
FocusDraw();
AdjustTextWidth(true);
::TEClick(inMouseDown.whereLocal,
((inMouseDown.macEvent.modifiers & shiftKey) != 0),
mBulletTextEditH);
// Since TEClick holds on to the mouse until the user lets go,
// we need to manually match up the selection of the hidden
// TextEdit record to that of the visible one.
(*mTextEditH)->selStart = (*mBulletTextEditH)->selStart;
(*mTextEditH)->selEnd = (*mBulletTextEditH)->selEnd;
AdjustTextWidth(false);
}
}
//=============================================================================
// LPasswordField::ObeyCommand
//-----------------------------------------------------------------------------
// Handle standard editing commands.
//-----------------------------------------------------------------------------
Boolean LPasswordField::ObeyCommand(CommandT inCommand, void *ioParam)
{ Boolean cmdHandled = true;
Int32 offset;
// Case out on the command
switch (inCommand) {
case cmd_Cut:
::TECut(mTextEditH);
PostAction(new LTECutAction(mBulletTextEditH, this, this));
break;
case cmd_Copy:
::TECopy(mBulletTextEditH);
::ZeroScrap();
::TEToScrap();
break;
case cmd_Paste:
// If pasting would exceed the maximum field size, we beep
if (TooManyCharacters(::GetScrap(nil, 'TEXT', &offset)))
::SysBeep(30);
// Otherwise, past it in to both records. We need to move
// the visible TextEdit record off screen while pasting,
// since we need to munge the characters to bullets after
// they've been pasted in.
else
{
// Paste it into the off screen record
PostAction(new LTEPasteAction(mTextEditH, this, this));
// Move the visible text record off the screen
OffsetRect(&(*mBulletTextEditH)->viewRect, 5000, 5000);
// Paste in the text, and convert it to bullets
PostAction(new LTEPasteAction(mBulletTextEditH, this, this));
SetTextToBullets(mBulletTextEditH);
// Move the visible text record back onto the screen and redraw
OffsetRect(&(*mBulletTextEditH)->viewRect, -5000, -5000);
AlignTextEditRects();
Refresh();
}
break;
case cmd_Clear:
::TEDelete(mTextEditH);
PostAction(new LTEClearAction(mBulletTextEditH, this, this));
break;
default:
// Our parent is an LEditField, not an LCommander
cmdHandled = LEditField::ObeyCommand(inCommand, ioParam);
break;
}
// Return as the command was handled or not
return cmdHandled;
}
//=============================================================================
// LPasswordField::FindCommandStatus
//-----------------------------------------------------------------------------
// Pass back the status of a command.
//
// We don't *really* need to override this, since all of our commands
// are tied to the current selection (which should be the same in
// both the visible and off screen TextEdit records).
//
// But, we override just to make sure we can get the behaviour we want.
//-----------------------------------------------------------------------------
void LPasswordField::FindCommandStatus(CommandT inCommand,
Boolean &outEnabled,
Boolean &outUsesMark,
Char16 &outMark,
Str255 outName)
{
// Case out on the command
switch (inCommand) {
case cmd_Cut:
case cmd_Copy:
case cmd_Clear:
// Cut, copy, and clear are enabled if something is selected
outEnabled = ((**mBulletTextEditH).selStart != (**mBulletTextEditH).selEnd);
break;
case cmd_SelectAll:
// We can only select everything if there's something to select
outEnabled = (**mBulletTextEditH).teLength > 0;
break;
default:
// Pass it to the LEditField if it's anything else
LEditField::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
break;
}
}
//=============================================================================
// LPasswordField::HandleKeyPress
//-----------------------------------------------------------------------------
// Handle a key stroke directed at a PasswordField.
//
// We return true if we handle the keystroke.
//-----------------------------------------------------------------------------
Boolean LPasswordField::HandleKeyPress(const EventRecord &inKeyEvent)
{ Boolean keyHandled = true;
EKeyStatus theKeyStatus = keyStatus_Input;
Int16 theKey = inKeyEvent.message & charCodeMask;
// We always pass it up when the command key is down
if (inKeyEvent.modifiers & cmdKey)
theKeyStatus = keyStatus_PassUp;
else if (mKeyFilter != nil)
theKeyStatus = (*mKeyFilter)(inKeyEvent);
// Case out on theKeyStatus
switch (theKeyStatus) {
case keyStatus_Input:
// Check to see if we're at the character limit.
// This is NOT compatible with two-byte character systems
if (TooManyCharacters(1))
{
SysBeep(30);
break;
}
// Otherwise, put the keystroke into the real TextEdit record
TEKey(theKey, mTextEditH);
// Turn the key into a bullet
theKey = mBullet;
// Put the bullet character into the visible TextEdit record
if (mTypingAction == nil)
{
mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
PostAction(mTypingAction);
}
if (mTypingAction != nil)
mTypingAction->InputCharacter(theKey);
else
::TEKey(theKey, mBulletTextEditH);
UserChangedText();
break;
case keyStatus_TEDelete: {
if ((**mBulletTextEditH).selEnd > 0)
{
// Do it to the hidden text edit field
::TEKey(char_Backspace, mTextEditH);
// Do it to the visible text edit field
if (mTypingAction == nil)
{
mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
PostAction(mTypingAction);
}
if (mTypingAction != nil)
mTypingAction->BackwardErase();
else
::TEKey(char_Backspace, mBulletTextEditH);
UserChangedText();
}
break; }
case keyStatus_TECursor: {
StFocusAndClipIfHidden teCursorFocus(this);
::TEKey(theKey, mTextEditH);
::TEKey(theKey, mBulletTextEditH);
break; }
case keyStatus_ExtraEdit: {
StFocusAndClipIfHidden extraEditFocus(this);
switch (theKey) {
case char_Home:
::TESetSelect(0, 0, mTextEditH);
::TESetSelect(0, 0, mBulletTextEditH);
break;
case char_End:
::TESetSelect(max_Int16, max_Int16, mTextEditH);
::TESetSelect(max_Int16, max_Int16, mBulletTextEditH);
break;
case char_FwdDelete:
if ((**mBulletTextEditH).selStart < (**mBulletTextEditH).teLength)
{
// Do it to the hidden record
if ((**mTextEditH).selStart == (**mTextEditH).selEnd)
::TESetSelect((**mTextEditH).selStart,
(**mTextEditH).selStart + 1,
mTextEditH);
::TEDelete(mTextEditH);
// Do it to the visible record
if (mTypingAction == nil)
{
mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
PostAction(mTypingAction);
}
if (mTypingAction != nil)
mTypingAction->ForwardErase();
else
if ((**mBulletTextEditH).selStart == (**mBulletTextEditH).selEnd)
::TESetSelect((**mBulletTextEditH).selStart,
(**mBulletTextEditH).selStart + 1,
mTextEditH);
::TEDelete(mTextEditH);
UserChangedText();
}
break;
default:
keyHandled = LEditField::HandleKeyPress(inKeyEvent);
break;
}
break; }
case keyStatus_Reject:
// Can do something with rejected keystrokes here
SysBeep(30);
break;
case keyStatus_PassUp:
keyHandled = LEditField::HandleKeyPress(inKeyEvent);
break;
}
// Return as the keystroke was handled or not
return(keyHandled);
}
//=============================================================================
// LPasswordField::SelectAll
//-----------------------------------------------------------------------------
// Select the entire contents of a PasswordField.
//-----------------------------------------------------------------------------
void LPasswordField::SelectAll()
{
// Call our parent class
LEditField::SelectAll();
// Select the visible TextEdit record
StFocusAndClipIfHidden focus(this);
::TESetSelect(0, max_Int16, mBulletTextEditH);
}
//=============================================================================
// LPasswordField::AlignTextEditRects
//-----------------------------------------------------------------------------
// Align the view and destination rectangles of the Toolbox TextEdit
// records with the Frame of a PasswordField.
//-----------------------------------------------------------------------------
void LPasswordField::AlignTextEditRects()
{ Rect textFrame;
// If the Frame is outside QuickDraw space, we put textFrame at
// the upper left limit of QuickDraw space (extreme negative
// coordinates). That location is gauranteed to be offscreen
// (unless you have a control longer than 32K pixels). since
// PowerPlant Image coordinates start at (0, 0) and are never
// negative.
if (!CalcLocalFrameRect(textFrame))
{
textFrame.left = min_Int16;
textFrame.right = textFrame.left + mFrameSize.width;
textFrame.top = min_Int16;
textFrame.bottom = textFrame.top + mFrameSize.height;
}
// If we have a box, move in past it
if (mHasBox)
::InsetRect(&textFrame, 2, 2);
// Set the TextEdit view and destination rectangles to be the
// same as the Frame. We do *not* set the viewRect of the
// mTextEditH TextEdit record, since that's what's keeping it
// off screen and out of the way.
// (**mTextEditH).viewRect = textFrame;
(**mTextEditH).destRect = textFrame;
(**mBulletTextEditH).viewRect = textFrame;
(**mBulletTextEditH).destRect = textFrame;
AdjustTextWidth(false);
// Let TextEdit adjust the line breaks
::TECalText(mTextEditH);
::TECalText(mBulletTextEditH);
}
//=============================================================================
// LPasswordField::AdjustTextWidth
//-----------------------------------------------------------------------------
// Adjust the width of the destination rectangle of the Toolbox TextEdit
// record
//
// This function does nothing if WordWrap is ON. If WordWrap is OFF, this
// function sets the width of the TextEdit destination rectangle to either
// the width of the text or a very large number, depending on the value
// of inShrinkToText.
//
// This adjustment is needed to make autoscrolling work properly when
// WordWrap is off. While entering text, the destination rectangle should
// be very wide so that the text doesn't word wrap. However, while
// clicking, it should be just as wide as the text so that the PassField
// does not autoscroll past the edge of the text.
//-----------------------------------------------------------------------------
void LPasswordField::AdjustTextWidth(Boolean inShrinkToText)
{ Rect textFrame;
Int16 destWidth = 4000; // Very Large Number
Int16 just;
// We adjust only of WordWrap is OFF
if (!mHasWordWrap)
{
// Get the size of the editable text area, taking into account a box
CalcLocalFrameRect(textFrame);
if (mHasBox)
::InsetRect(&textFrame, 2, 2);
// Calculate the width of the text in the PasswordField
if (inShrinkToText)
{
Point startPoint = ::TEGetPoint(0, mBulletTextEditH);
Point endPoint = ::TEGetPoint((**mBulletTextEditH).teLength, mBulletTextEditH);
destWidth = endPoint.h - startPoint.h;
if (destWidth < textFrame.right - textFrame.left)
destWidth = textFrame.right - textFrame.left;
}
// Direction to extend dest rect depends on the text justification
just = (**mBulletTextEditH).just;
if (just == teFlushDefault)
{
// For left justificaton, GetSysDirection returns teFlushDefault.
// For right, it returns teFlushRight
just = ::GetSysDirection();
}
// Case out on the justification
switch ((**mBulletTextEditH).just) {
case teFlushLeft:
case teFlushDefault:
// Text fixed on left and grows right
(**mBulletTextEditH).destRect.right = (**mBulletTextEditH).destRect.left + destWidth;
break;
case teFlushRight:
// Text grows to the left
(**mBulletTextEditH).destRect.left = (**mBulletTextEditH).destRect.right - destWidth;
break;
case teCenter:
// Text grows left and right
Int16 center = (textFrame.left + textFrame.right) / 2;
(**mBulletTextEditH).destRect.left = center - 2000;
(**mBulletTextEditH).destRect.right = center + 2000;
break;
}
}
}
//=============================================================================
// LPasswordField::BeTarget
//-----------------------------------------------------------------------------
// A PasswordField is becoming the target.
//-----------------------------------------------------------------------------
void LPasswordField::BeTarget()
{
// Call our parent class
LEditField::BeTarget();
// Show the active selection
::TEActivate(mBulletTextEditH);
}
//=============================================================================
// LPasswordField::DontBeTarget
//-----------------------------------------------------------------------------
// PasswordField is no longet the target.
//
// Our parent removes the PasswordField from the IdleQueue.
//-----------------------------------------------------------------------------
void LPasswordField::DontBeTarget()
{
// Call our parent class
LEditField::DontBeTarget();
// Show the inactive selection
::TEDeactivate(mBulletTextEditH);
}
//=============================================================================
// LPasswordField::SpendTime
//-----------------------------------------------------------------------------
// At idle time, we flash the insertion cursor if necessary.
//-----------------------------------------------------------------------------
void LPasswordField::SpendTime(const EventRecord &inMacEvent)
{
// Flash the cursor
if (FocusExposed())
::TEIdle(mBulletTextEditH);
}
//=============================================================================
// LPasswordField::SavePlace
//-----------------------------------------------------------------------------
// Save the TextEdit rectangles.
//-----------------------------------------------------------------------------
void LPasswordField::SavePlace(LStream *outPlace)
{
LPane::SavePlace(outPlace);
Rect viewRect = (**mBulletTextEditH).viewRect;
outPlace->WriteData(&viewRect, sizeof(Rect));
Rect destRect = (**mBulletTextEditH).destRect;
outPlace->WriteData(&destRect, sizeof(Rect));
}
//=============================================================================
// LPasswordField::RestorePlace
//-----------------------------------------------------------------------------
// Restore the TextEdit rectangles.
//-----------------------------------------------------------------------------
void LPasswordField::RestorePlace(LStream *inPlace)
{
LPane::RestorePlace(inPlace);
Rect viewRect;
inPlace->ReadData(&viewRect, sizeof(Rect));
(**mBulletTextEditH).viewRect = viewRect;
Rect destRect;
inPlace->ReadData(&destRect, sizeof(Rect));
(**mBulletTextEditH).destRect = destRect;
}
//=============================================================================
// LPasswordField::SetTextToBullets
//-----------------------------------------------------------------------------
// Set every character in a TextEdit record to be the bullet character.
//-----------------------------------------------------------------------------
void LPasswordField::SetTextToBullets(TEHandle theTextHnd)
{ char *theChar;
short i, theLen;
// Get the text, and it's length
theChar = *(::TEGetText(theTextHnd));
theLen = (*theTextHnd)->teLength;
// If there's no text, we're done
if (theLen == 0)
return;
// Set every character to the bullet character
for (i = 0; i < theLen; i++)
*theChar++ = mBullet;
}
//=============================================================================
// LPasswordField::SetVisibleFromHidden
//-----------------------------------------------------------------------------
// Set every character in mBulletTextEditH to be a bullet character,
// adjusting it's length to match mTextEditH if needs be.
//
// mBulletTextEditH is *not* redrawn - call Refresh() after calling this
// routine.
//-----------------------------------------------------------------------------
void LPasswordField::SetVisibleFromHidden(void)
{ CharsHandle theHnd;
char *theChar;
short i, theLen;
// Find out how much text is in the off screen TextEdit record
theHnd = ::TEGetText(mTextEditH);
::HLock(theHnd);
theChar = *theHnd;
theLen = (*mTextEditH)->teLength;
// Set the text of the on screen TextEdit record to match the offscreen
::TESetText(theChar, theLen, mBulletTextEditH);
// Unclock the text handle of the off screen TextEdit record
::HUnlock(theHnd);
// Convert the text of the on screen record to bullets
SetTextToBullets(mBulletTextEditH);
}